package com.apestech.framework.util;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 与数字计算有关的函数方法合集，向上、下取整，四舍五入均取自JAVA原生中正数的计算规则，引入了移位方式的加减乘除，但要注意仅只支持整数入参及返回<br>
 * 支持double，BigDecimal类型，其它类型根据实际需求再补充<br>
 * @author hupo
 *
 */
public class MathUtil extends MessageUtil {
	
	/**
     * 提供精确加法计算的add方法
     * @param value1 被加数
     * @param value2 加数
     * @return 两个参数的和
     */
    public static double add(double value1,double value2){
    	StringBuilder val1=new  StringBuilder(Double.toString(value1));
    	StringBuilder val2=new  StringBuilder(Double.toString(value2));
        BigDecimal b1 = new BigDecimal(val1.toString());
        BigDecimal b2 = new BigDecimal(val2.toString());
        return b1.add(b2).doubleValue();
    }
    
    /**
     * 提供精确减法运算的sub方法
     * @param value1 被减数
     * @param value2 减数
     * @return 两个参数的差
     */
    public static double sub(double value1,double value2){
    	String val1=Double.toString(value1);
    	String val2=Double.toString(value2);
        BigDecimal b1 = new BigDecimal(val1);
        BigDecimal b2 = new BigDecimal(val2);
        return b1.subtract(b2).doubleValue();
    }
    
    /**
     * 提供精确乘法运算的mul方法
     * @param value1 被乘数
     * @param value2 乘数
     * @return 两个参数的积
     */
    public static double mul(double value1,double value2){
    	String val1=Double.toString(value1);
    	String val2=Double.toString(value2);
        BigDecimal b1 = new BigDecimal(val1);
        BigDecimal b2 = new BigDecimal(val2);
        return b1.multiply(b2).doubleValue();
    }
    
    /**
     * 提供精确的除法运算方法div
     * @param value1 被除数
     * @param value2 除数
     * @return 两个参数的商
     * @throws IllegalAccessException
     */
    public static double div(double value1,double value2) throws IllegalAccessException{
        String val1=Double.toString(value1);
    	String val2=Double.toString(value2);
        BigDecimal b1 = new BigDecimal(val1);
        BigDecimal b2 = new BigDecimal(val2);
        return b1.divide(b2,17, RoundingMode.HALF_UP).doubleValue();
    }
    
    /**
	 * 按设定小数位数向下取数，用MATH中floor正数处理逻辑处理负数规则，整数示例：-1.1 -1.0;  0.6 0.0;  15.7 15.0   
	 * @param d
	 * @param scale
	 * @return
	 */
	public static double floor(double d,int scale){
		double minus=1;
		if(d<0){
			minus=-1;
		}
		d=Math.abs(d);
		double len=getScale(scale);
		return minus*(Math.floor(d*len)/len);
	}
	
	/**
	 * 按设定小数位数向下取数，用MATH中floor正数处理逻辑处理负数规则，整数示例：-1.1 -1.0;  0.6 0.0;  15.7 15.0   
	 * @param d
	 * @param scale
	 * @return
	 */
	public static double floor(BigDecimal d,int scale){
		return floor(d.doubleValue(),scale);
	}
	
	/**
	 * 按设定小数位数向上取数，用MATH中ceil正数处理逻辑处理负数规则，整数示例：-1.6 -2.0;  0.1 1.0;  1.1 2.0
	 * @param d
	 * @param scale
	 * @return
	 */
	public static double ceil(double d,int scale){
		double minus=1;
		if(d<0){
			minus=-1;
		}
		d=Math.abs(d);
		double len=getScale(scale);
		return minus*(Math.ceil(d*len)/len);
	}
	
	/**
	 * 按设定小数位数向上取数，用MATH中ceil正数处理逻辑处理负数规则，整数示例：-1.6 -2.0;  0.1 1.0;  1.1 2.0
	 * @param d
	 * @param scale
	 * @return
	 */
	public static double ceil(BigDecimal d,int scale){
		return ceil(d.doubleValue(),scale);
	}
	
	/**
	 * 按设定小数位数四舍五入，用MATH中round正数处理逻辑处理负数规则，整数示例：-1.1 -1.0;  -1.6 -2.0;  0.5 1.0;  0.6 1.0
	 * @param d
	 * @param scale
	 * @return
	 */
	public static double round(double d,int scale){  
		double minus=1;
		if(d<0){
			minus=-1;
		}
		d=Math.abs(d);
		double len=getScale(scale);
		return minus*(Math.round(d*len)/len);
	}
	
	/**
	 * 按设定小数位数四舍五入，用MATH中round正数处理逻辑处理负数规则，整数示例：-1.1 -1.0;  -1.6 -2.0;  0.5 1.0;  0.6 1.0
	 * @param d
	 * @param scale
	 * @return
	 */
	public static double round(BigDecimal d,int scale){  
		return round(d.doubleValue(),scale);
	}

	/**
	 * 移位方式加法运算
	 * @param a
	 * @param b
	 * @return
	 */
	public static int shiftAdd(int a,int b) {
        int res=a;
        int xor=a^b;//得到原位和
        int forward=(a&b)<<1;//得到进位和
        if(forward!=0){//若进位和不为0，则递归求原位和+进位和
            res=shiftAdd(xor, forward);
        }else{
            res=xor;//若进位和为0，则此时原位和为所求和
        }
        return res;                
    }
	
	/**
	 * 获取小数位数和
	 * @param scale
	 * @return
	 */
	private static int getScale(int scale){
		int len=1;
		if(scale<-1){
			scale=0;
		}
		for(int i=1;i<=scale;i++){
			len=shiftMul(len,10);
		}
		return len;
	}	
	
	private static int toInt(double num, int scale){
		int len=getScale(scale+1);
		int abs=1;
		if(num<0){
			abs=-1;
		}
		num=Math.abs(num)*len;
		int inum=(int) Math.floor(num);
		inum=shiftMul(inum,abs);
		return inum;
	}
	
	/*public static double shiftAdd(double a,double b,int scale) {
		int a1=toInt(a, scale);
		int b1=toInt(b, scale);
		int c=shiftAdd(a1,b1);
		int len=getScale(scale+1);
		int inum=shiftDiv(c,len);
		//123.4564+456.78945
		//123456+456789=580245
		return shiftDiv(c,int b);
	}*/
	
	/**
	 * 移位方式减法运算
	 * @param a
	 * @param b
	 * @return
	 */
	public static int shiftSub(int a,int b) {
        int B=~(b-1);
        return shiftAdd(a, B);        
    }
	
	/**
	 * 移位方式乘法运算
	 * @param a
	 * @param b
	 * @return
	 */
	public static int shiftMul(int a,int b){
        int i=0;
        int res=0;
        while(b!=0){//乘数为0则结束
            //处理乘数当前位
            if((b&1)==1){
                res+=(a<<i);
                b=b>>1;
                ++i;//i记录当前位是第几位
            }else{
                b=b>>1;
                ++i;
            }
        }
        return res;
    }
	
	/**
	 * 移位方式除法运算
	 * @param a
	 * @param b
	 * @return
	 */
	public static int shiftDiv(int a,int b) {
        int res=-1;
        if(a<b){
            return 0;
        }else{
            res=shiftDiv(shiftSub(a, b), b)+1;
        }
        return res;
    }
	
	

}
